// Author: Bjorn Schobben

#include "Highscore.h"


using namespace std;

Highscore::Highscore()
{
	highscores.reserve(MAXSCORECOUNT+1);
}

Highscore::Highscore(const Highscore &rhs): highscores(rhs.highscores)
{
}

Highscore::~Highscore()
{
	Clear();
}

void Highscore::Clear()
{
	highscores.clear();
}

void Highscore::WriteScore(std::ofstream& f, const Score& score) const
{
	const string& name = score.GetName();
	unsigned int length = (unsigned int)name.length();
	unsigned int colorCount = score.GetColorCount();
	unsigned int time = score.GetTime();
	unsigned int stepCount = score.GetStepCount();

	// Save length of string
	f.write((char*)&length, sizeof(length));
	// Save string data
	f.write(name.c_str(), length);
	// Save color count, time and step count
	f.write((char*)&colorCount, sizeof(colorCount));
	f.write((char*)&time, sizeof(time));
	f.write((char*)&stepCount, sizeof(stepCount));
}

void Highscore::ReadScore(std::ifstream& f, Score* score) const
{
	unsigned int length;
	unsigned int colorCount;
	unsigned int time;
	unsigned int stepCount;

	std::string name;

	// Get length of string
	f.read((char*)&length, sizeof(length));

	// If file is ended, return
	if (f.eof())
		return;

	// Temporarily read into a char array, then convert to string
	char *tmp = new char[length];
	f.read(tmp, length);
	name.assign(tmp, length);
	delete[] tmp;

	// Get color count, time and stepcount
	f.read((char*)&colorCount, sizeof(colorCount));
	f.read((char*)&time, sizeof(time));
	f.read((char*)&stepCount, sizeof(stepCount));

	// If file is ended, return
	if (f.eof())
		return;

	score->SetName(name);
	score->SetStepCount(stepCount);
	score->SetTime(time);
	score->SetColorCount(colorCount);
}

//Load the highscore vector from a file
bool Highscore::LoadFromFile(const std::string& readFilename)
{
	bool result = false;
	filename = readFilename;

	Clear();

	// Binary file
	ifstream f(readFilename.c_str(), ios::in | ios::binary);

	// While file is still in a good shape
	while(!f.eof() && f.good() && !f.bad() && !f.fail())
	{
		Score score;

		ReadScore(f, &score);

		// If file is ended, return
		if (f.eof())
			break;

		// Insert score
		InsertScore(score);

		// Loaded atleast one highscore entry successfully
		result = true;
	}

	return result;
}

//Save the highscore vector to a file
bool Highscore::SaveToFile(const std::string& saveFilename) const
{
	bool result;
	std::vector<Score>::const_iterator it;
	ofstream f(saveFilename.c_str(), ios::out | ios::binary);

	for(it = highscores.begin(); it != highscores.end(); ++it)
	{
		const Score& score = *it;

		// While we can still write to the file
		if (f.good() && !f.bad() && !f.fail())
		{
			WriteScore(f, score);
		}
	}

	// If file is still good, then file was saved successfully
	if (f.good() && !f.bad() & !f.fail())
	{
		result = true;
	}

	return result;
}

// Save current highscores to the file it was loaded from
void Highscore::Save() const
{
	if (filename.length())
	{
		SaveToFile(filename);
	}
}

// Test if score will be inserted to the highscores
bool Highscore::TestScoreInsert(const Score &score) const
{
	bool result = false;

	result = (highscores.size() < MAXSCORECOUNT) || (score < highscores.back());

	return result;
}

//Insert a score into the highscore vector
void Highscore::InsertScore(const Score &score)
{
	highscores.push_back(score);
	
	std::sort(highscores.begin(),highscores.end());

	//The highscore vector is not allowed to have more then 10 entries
	if(highscores.size() > MAXSCORECOUNT)
		highscores.pop_back();
}

//Return the highscore vector
const std::vector<Score>& Highscore::GetScores() const
{
	return highscores;
}
